﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;


namespace HomeController
{
    public class TcpListener
    {
        private SocketAsyncEventArgs Args;
        private Socket ListenerSocket;
        StringBuilder buffers;

        public TcpListener() { }

        public static EndPoint GetIp()
        {
            //IPAddress myIP;
            //IPAddress.TryParse("192.168.1.105", out myIP);
            //return new IPEndPoint(myIP, 5288);
            return new IPEndPoint(IPAddress.Any, 5288);
        }

        public void Listen(EndPoint e)
        {
            buffers = new StringBuilder();
            //socket
            ListenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            ListenerSocket.Bind(e);
            ListenerSocket.Listen(10);
            //异步socket事件
            Args = new SocketAsyncEventArgs();
            Args.Completed += new EventHandler<SocketAsyncEventArgs>(ProcessAccept);
            BeginAccept(Args);
        }

        //开始接受
        void BeginAccept(SocketAsyncEventArgs e)
        {
            e.AcceptSocket = null;
            if (!ListenerSocket.AcceptAsync(e))
                ProcessAccept(ListenerSocket, e);
        }

        //接受完毕 开始接收和发送
        void ProcessAccept(object sender, SocketAsyncEventArgs e)
        {
            Socket s = e.AcceptSocket;
            e.AcceptSocket = null;

            int bufferSize = 10;//1000 * 1024;
            var args = new SocketAsyncEventArgs();
            args.Completed += new EventHandler<SocketAsyncEventArgs>(OnIOCompleted);
            args.SetBuffer(new byte[bufferSize], 0, bufferSize);
            args.AcceptSocket = s;
            if (!s.ReceiveAsync(args))
                this.ProcessReceive(args);

            BeginAccept(e);
        }

        //IOCP回调
        void OnIOCompleted(object sender, SocketAsyncEventArgs e)
        {
            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Receive:
                    this.ProcessReceive(e);
                    break;
                case SocketAsyncOperation.Send:
                    this.ProcessSend(e);
                    break;
                default:
                    throw new ArgumentException("The last operation completed on the socket was not a receive or send");
            }
        }

        //接收完毕
        void ProcessReceive(SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0)
            {
                if (e.SocketError == SocketError.Success)
                {
                    //读取
                    var data = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
                    buffers.Append(data);
                    if (e.AcceptSocket.ReceiveBufferSize == 0)
                    {
                        //读取完毕
                        var result = buffers.ToString();
                        //发送反馈
                        Byte[] sendBuffer = Encoding.UTF8.GetBytes("result from server");
                        e.SetBuffer(sendBuffer, 0, sendBuffer.Length);
                        if (!e.AcceptSocket.SendAsync(e))
                        {
                            this.ProcessSend(e);
                        }
                    }
                    else if (!e.AcceptSocket.ReceiveAsync(e))
                    {
                        this.ProcessReceive(e);
                    }
                }
                else
                {
                    //this.ProcessError(e);
                }
            }
            else
            {
                //this.CloseClientSocket(e);
            }
        }

        //发送完毕
        void ProcessSend(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                if (!e.AcceptSocket.ReceiveAsync(e))
                {
                    this.ProcessReceive(e);
                }
            }
            else
            {

            }
        }
    }
}